﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Javascript algorithm benchmarker</title>
		<!-- YUI --> 
		<script type="text/javascript" src="http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader-min.js"></script>	
		<script type="text/javascript"> 
		(function() { 
		    var loader = new YAHOO.util.YUILoader({ 
		        base: "", 
		        require: ["datatable","treeview"], 
		        loadOptional: false, 
		        combine: true, 
		        filter: "MIN", 
		        allowRollup: true
		    }); 
		loader.insert(); 
		})(); 
		</script>  
		<!-- jquery -->
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.min.js"></script>

		<!-- own -->
		<script type="text/javascript" src="benchmark.js"></script>
		<script type="text/javascript" src="algorithms.js"></script>

		<script type="text/javascript">	// An example of benchmarking. Array.sort() is benchmarked and then the results are displayed.
			/**
			 * @param n {Number} how many random numbers
			 * @return {Array} an array of random numbers
			 */
			randomNumbers = function(n) {
				var randomNumberCount = n; // How many random numbers.
				var randomNumbers = new Array();
					
				var upper = n;
				var lower = 0;
				for (var i = 0; i < randomNumberCount; i++) {
					randomNumbers.push(
						// A random number within the range.
						Math.floor((upper-(lower-1))*Math.random()) + lower
					);
				}
				
				return randomNumbers;
			}

			/**
			 * View the benchmark results.
			 *
			 * @param {Array} an array of BenchmarkResults arrays
			 * @dependencies YUI data table, JQuery, benchmark.js
			 */
			viewResults = function(benchmarkResultsArray) {
			
					/**
					 * Render a chart on the benchmark results.
					 */
					var renderChart = function() {
						var chartResolution = "300x300";
						var url = buildChartUrl({resolution: chartResolution}, benchmarkResultsArray);			

						var img = document.createElement("img");
						$(img).attr("src", url);	
						$(img).css("width", "300px");
						$(img).css("height", "300px");

						$("#chartImage").empty();
						document.getElementById("chartImage").appendChild(img);
						return this;
					}

					/**
					 * Render a table that displays running time statistics.
					 */
					var renderRunningTimeTable = function() {	
						var dataSourceArray = new Array();
						// Loop the array containing arrays of BenchmarkResult instances
						for (j = 0; j < benchmarkResultsArray.length; j++) { 
							var benchmarkResults = benchmarkResultsArray[j]; // An array of BenchmarkResult instances
							for (var i = 0; i < benchmarkResults.length ; i++) {
								var result = benchmarkResults[i]; // A BenchmarkResult instance
								dataSourceArray.push( {
									n: result.getN(), 
									min:result.getRunningTimeInfo().getMin(),
									max:result.getRunningTimeInfo().getMax(),
									avg:result.getRunningTimeInfo().getAverage(),
									median:result.getRunningTimeInfo().getMedian()
								} );					
							}
						}

						var columnDefs = [
							{key:"n", label:"N"},
							{key:"min", label:"Min"},
							{key:"avg", label:"Average"},
							{key:"median", label:"Median"},
							{key:"max", label:"Max"}
						];

						var dataSource = new YAHOO.util.LocalDataSource(dataSourceArray);

						var myDataTable = new YAHOO.widget.DataTable("runningTimesTableDiv", columnDefs, dataSource); 
						$("#runningTimesTableDiv table").css("margin", "auto");
					}

					renderChart();
					renderRunningTimeTable();
			}

			var benchmarkSuite;
			
			/**
			 * @return {Array{Number}} the n set from the user
			 * @dependencies JQuery
			 */
			collectN = function() {
				var nArray = new Array(); // N array
				var inputValues = $("#nSet").val().split(","); // From the input field
				for (var key in inputValues) {
					if (isNaN(inputValues[key]))
						continue;
					nArray.push(new Number(inputValues[key]));
				}
				return nArray;
			}
	
			/**
			 * Initializes the navigation panel.
			 * @param {BenchmarkSuite} a benchmarkSuite instance
			 * @dependencies JQuery, JQuery ui, benchmark.js, algorithm.js
			 */
			initNavigationPanel = function(benchmarkSuite) {
				$("#accordion").accordion();
				$("#accordion input").each(function() { 
					$(this).bind("click", function() {
						var algorithmName = $(this).attr("id");
						if ($(this).is(":checked")) {
							benchmarkSuite.add(algorithmName, new InputGenerator(randomNumbers), getAlgorithm(algorithmName));					
						} else {
							benchmarkSuite.remove(algorithmName);
						}
					}); 
				});
			}

			/**
			 * Init the application and make it ready for use.
			 * @dependencies benchmark.js, JQuery
			 */
			initApp = function() {
				benchmarkSuite = new BenchmarkSuite();
				var algorithmRenderer = new BenchmarkSuite.Renderer.SingleAlgorithmRenderer({
					algorithmAddRenderer: function(algorithmInstance) {
						// Handle algorithm-add rendering
						$("#suiteDiv #algorithms").text(algorithmInstance.getName());
						},
					algorithmRemoveRenderer: function(algorithmInstance) {
						// Handle algorithm-remove rendering
						$("#suiteDiv #algorithms").text("remove");
						}
				});
				var containerRenderer = new BenchmarkSuite.Renderer.SuiteContainerRenderer({
					initialRenderer: function() {
							
					}
				});
				var suiteRenderer = new BenchmarkSuite.Renderer(algorithmRenderer, containerRenderer);
				benchmarkSuite.setRenderer(suiteRenderer);
				benchmarkSuite.init();

				initNavigationPanel(benchmarkSuite);
			}

			$(document).ready(function() {
				initApp();
				$("#goButton").bind("click", function() { // The launch button's function
					var inputGenerator = new InputGenerator(randomNumbers);
				
					var repetitions = new Number($("#repetitions").val());
					var nArray = collectN();
					benchmarkSuite.setBenchmarkParams({nArray:nArray, repetitions:repetitions});		

					var benchmarkResults = benchmarkSuite.runBenchmarks();
			
					viewResults(benchmarkResults); // Do display
				});
			});
		</script>
		<link rel="stylesheet" type="text/css" href="css/style.css">
	</head>
	<body>
		<div id="container">
			<div id="maincontent">
				<div id="header">
					<h2>Javascript algorithm benchmarker</h2>
				</div>
				<div id="controls">
					<p>
						Repetitions: <input id="repetitions" type="text" value="5">
					</p>
					<p>
						Random number data sets: <input id="nSet" type="text" value="5000, 10000, 15000">
						<input id="goButton" type="button" value="go!">
					</p>
				</div>
				<div id="chartImage"></div>
				<div id="runningTimesTableDiv"></div>
	
			</div>
			<div id="navigation">
				<h4>
					Select the algorithms to compare
				</h4>
				<ul id="accordion" class="ui-accordion-container"> 
				    <li> 
				        <span class="ui-accordion-left"></span> 
				        <a href='#' class="ui-accordion-link"> 
				            Sorting algorithms ...
				            <span class="ui-accordion-right"></span> 
				        </a> 
				        <div class="ui-accordion-data">
						<ul class="accordion-data">
							<li><input type="checkbox" id="nativeArraySort">native Array.sort()</li>
							<li><input type="checkbox" id="mergeSort">merge sort</li>
							<li><input type="checkbox" id="quickSort">quick sort</li>
							<li><input type="checkbox" id="heapSort">heap sort</li>
						</ul>
				        </div> 
				    </li> 
				    <li> 
				        <span class="ui-accordion-left"></span> 
				        <a href='#' class="ui-accordion-link">Other algorithms ...<span class="ui-accordion-right"></span></a> 
				        <div  class="ui-accordion-data">TODO
				        </div> 
				    </li> 
				</ul>
			</div>
			<div id="suiteDiv">
				<h4>Benchmark suite</h4>
				<div id="algorithms"></div>
			</div>
		</div>
	</body>
</html>

